<template>
	<div class="default-main">

		<cus-form id="user-form" collapsable icon="fa fa-search" label="搜索">
			<template #title-after>
				<el-button icon="el-icon-Search" size="small" type="primary" @click.stop="handleSearch">
					搜索
				</el-button>
				<el-button icon="el-icon-Refresh" size="small" type="primary" @click.stop="resetSearch">
					重置
				</el-button>
			</template>
			<template #form>
				<el-form ref="searchForm" :model="params" label-width="auto">
					<el-row :gutter="20" justify="space-between">
						<el-col :span="8">
							<el-form-item label="昵称">
								<el-input v-model="params.nickname_like" clearable placeholder="模糊查询" @keyup.enter="handleSearch"></el-input>
							</el-form-item>
						</el-col>
						<el-col :span="8">
							<el-form-item label="用户名">
								<el-input v-model="params.username_like" clearable placeholder="模糊查询" @keyup.enter="handleSearch"></el-input>
							</el-form-item>
						</el-col>
						<el-col :span="8">
							<el-form-item label="个人简介">
								<el-input v-model="params.introduction_like" clearable placeholder="模糊查询" @keyup.enter="handleSearch"></el-input>
							</el-form-item>
						</el-col>
					</el-row>
					<el-row :gutter="20" justify="start">
						<el-col :span="8">
							<el-form-item label="性别">
								<business-code-radio v-model="params.gender_eq" border code-type="gender" @change="handleSearch"/>
							</el-form-item>
						</el-col>
						<el-col :span="8">
							<el-form-item label="状态">
								<business-code-radio v-model="params.valid_eq" border code-type="userValid" @change="handleSearch"/>
							</el-form-item>
						</el-col>
						<el-col :span="8">
							<el-form-item label="已删除">
								<business-code-radio v-model="params.isDeleted_eq" border code-type="userDeleted" @change="handleSearch"/>
							</el-form-item>
						</el-col>
					</el-row>
					<el-row :gutter="20" justify="start">
						<el-col :span="8">
							<el-form-item label="绑定邮箱">
								<business-code-radio v-model="params.hasEmail" border code-type="shiFou" @change="handleSearch"/>
							</el-form-item>
						</el-col>
						<el-col :span="8">
							<el-form-item label="邮箱">
								<el-input v-model="params.email_like" clearable placeholder="模糊查询" @keyup.enter="handleSearch"></el-input>
							</el-form-item>
						</el-col>
					</el-row>
				</el-form>
			</template>
		</cus-form>

		<cus-table-title id="user-table-title" icon="local-cus-peoples" label="用户">
			<template #after>
				<el-button icon="el-icon-Plus" size="small" style="margin-left: 20px" type="primary" @click="toAdd">
					新增
				</el-button>
			</template>
		</cus-table-title>
		<el-table ref="tableRef" v-loading="tableLoading" :data="userTableData" :header-cell-class-name="handleHeaderCellClass" :max-height="tableMaxHeight" border
		          class="cus-table" fit highlight-current-row @sort-change="elTableSortChange($event, params.orderby, handleSearch)">
			<el-table-column align="center" label="序号" width="60">
				<template v-slot="scope">
					{{ initTableIndex(pageRef, scope.$index) }}
				</template>
			</el-table-column>
			<el-table-column align="center" label="昵称" min-width="150" prop="nickname" show-overflow-tooltip></el-table-column>
			<el-table-column align="center" label="用户名" min-width="150" prop="username" show-overflow-tooltip></el-table-column>
			<el-table-column align="center" label="性别" prop="gender" sortable="custom" width="100">
				<template v-slot="{row}">
					<el-tag v-if="row.gender === 1" type="info">{{ getBusinessCodeName('gender', row.gender) }}</el-tag>
					<el-tag v-else-if="row.gender === 2">{{ getBusinessCodeName('gender', row.gender) }}</el-tag>
					<el-tag v-else type="warning">{{ getBusinessCodeName('gender', row.gender) }}</el-tag>
				</template>
			</el-table-column>
			<el-table-column align="center" label="邮箱" min-width="150" prop="email" show-overflow-tooltip>
				<template v-slot="{row}">
					<el-text v-if="row.emailValid === 1">{{ row.email }}</el-text>
					<el-text v-else tag="del" type="info">{{ row.email }}</el-text>
				</template>
			</el-table-column>
			<el-table-column align="center" label="头像" prop="avatar" width="100">
				<template v-slot="{row}">
					<el-image v-if="row.avatar" :src="handleAvatarUrl(row.avatar)" style="width: 50px;height: auto;border-radius: 5px"></el-image>
				</template>
			</el-table-column>
			<el-table-column align="center" label="个人简介" min-width="450" prop="introduction"></el-table-column>
			<el-table-column :formatter="elTableDateTimeFormatter" align="center" label="注册时间" prop="createTime" width="170"></el-table-column>
			<el-table-column ref="validColumn" align="center" label="已删除" prop="isDeleted" sortable="custom" width="120">
				<template v-slot="{row}">
					<el-tag :type="row.isDeleted === 1 || row.isDeleted === 2 ? 'danger' : 'success'">{{ getBusinessCodeName('userDeleted', row.isDeleted) }}</el-tag>
				</template>
			</el-table-column>
			<el-table-column ref="validColumn" align="center" fixed="right" label="启用" prop="valid" sortable="custom" width="120">
				<template v-slot="{row}">
					<business-code-switch v-model="row.valid" :active-value="1" :before-change="() => beforeValidChange(row)"
					                      :disabled="!hasPermission('sys-user:updateAdminUserValid') || userStore.userId === row.id || row.isDeleted === 1"
					                      :inactive-value="0" :loading="validSwitchLoading" :show-text="false" code-type="userValid"/>
				</template>
			</el-table-column>
			<el-table-column :label="String($t('table.actions'))" align="center" fixed="right" width="150">
				<template v-slot="scope">
					<el-button icon="el-icon-Edit" size="small" type="primary" @click="toUpdate(scope.row)"></el-button>
					<el-dropdown style="margin-left: 10px">
						<el-button icon="el-icon-MoreFilled" plain round size="small"></el-button>
						<template #dropdown>
							<el-dropdown-menu>
								<el-dropdown-item :disabled="!hasPermission('sys-user:deleteUser') || scope.row.isDeleted === 1" icon="el-icon-Delete"
								                  @click="deleteUser(scope.row)">
									删除
								</el-dropdown-item>
								<el-dropdown-item :disabled="!hasPermission('sys-user:clearUserData')" icon="el-icon-Delete" @click="clearUserData(scope.row)">
									彻底删除
								</el-dropdown-item>
							</el-dropdown-menu>
						</template>
					</el-dropdown>
				</template>
			</el-table-column>
		</el-table>
		<cus-pagination id="user-pagination" ref="pageRef" v-model="userTableData" v-model:loading="tableLoading" :pageSize="10" :params="params"
		                url="/system/sys-user/readOnly/pageUser"/>

		<!-- 对话框（新增、修改） -->
		<el-dialog v-model="dialogVisible" :close-on-click-modal="false" :close-on-press-escape="true" :title="dialogTitle" append-to-body center class="cus-dialog"
		           destroy-on-close draggable width="50%">
			<el-form ref="editFormRef" :disabled="editFormDisabled" :model="user" :rules="rules" label-width="auto">
				<el-row :gutter="20" justify="space-between">
					<el-col :span="12">
						<el-form-item label="昵称" prop="nickname">
							<el-input v-model="user.nickname" clearable/>
						</el-form-item>
					</el-col>
					<el-col :span="12">
						<el-form-item label="用户名" prop="username">
							<el-input v-model="user.username" clearable/>
						</el-form-item>
					</el-col>
				</el-row>
				<el-row v-if="user.isDeleted === 1" :gutter="20" justify="space-between">
					<el-col :span="12">
						<el-form-item label="原昵称" prop="originalNickname">
							<el-tag type="info">{{ user.originalNickname }}</el-tag>
						</el-form-item>
					</el-col>
					<el-col :span="12">
						<el-form-item label="原用户名" prop="originalUsername">
							<el-tag type="info">{{ user.originalUsername }}</el-tag>
						</el-form-item>
					</el-col>
				</el-row>
				<el-row :gutter="20" justify="space-between">
					<el-col :span="12">
						<el-form-item label="角色" prop="roleList">
							<el-select v-model="user.roleList" clearable collapse-tags collapse-tags-tooltip filterable multiple value-key="id">
								<el-option v-for="role in roleOptionList" :key="role.id" :label="role.roleName!" :value="role"></el-option>
							</el-select>
						</el-form-item>
					</el-col>
					<el-col :span="12">
						<el-form-item label="启用" prop="valid">
							<el-switch v-model="user.valid" :active-value="1" :inactive-value="0"/>
						</el-form-item>
					</el-col>
				</el-row>
				<el-row :gutter="20" justify="space-between">
					<el-col :span="12">
						<el-form-item label="性别" prop="gender">
							<business-code-radio v-model="user.gender" border code-type="gender"/>
						</el-form-item>
					</el-col>
					<el-col :span="12">
						<el-form-item label="头像" prop="avatar">
							<el-input v-model="user.avatar" clearable/>
						</el-form-item>
					</el-col>
				</el-row>
				<el-row :gutter="20" justify="space-between">
					<el-col :span="12">
						<el-form-item label="邮箱" prop="email">
							<el-input v-model="user.email" clearable/>
						</el-form-item>
					</el-col>
					<el-col :span="12">
						<el-form-item label="邮箱激活" prop="emailValid">
							<business-code-switch v-model="user.emailValid" :active-value="1" :inactive-value="0" :show-text="false" code-type="emailValid"/>
						</el-form-item>
					</el-col>
				</el-row>
				<el-row :gutter="20" justify="space-between">
					<el-form-item label="邮件通知类型" prop="emailNotifyTypes">
						<business-code-checkbox v-model="user.emailNotifyTypes" code-type="emailNotifyType"/>
					</el-form-item>
				</el-row>
				<el-form-item label="个人简介" prop="introduction">
					<el-input v-model="user.introduction" :autosize="{ minRows: 4, maxRows: 4}" clearable type="textarea"/>
				</el-form-item>
				<el-form-item v-if="user.id" label="修改密码" prop="changePasswordFlag">
					<el-switch v-model="user.changePasswordFlag"></el-switch>
				</el-form-item>
				<el-row :gutter="20" justify="space-between">
					<el-col :span="12">
						<el-form-item v-if="!user.id || user.changePasswordFlag" label="密码" prop="password">
							<el-input v-model="user.password" clearable type="password"></el-input>
						</el-form-item>
					</el-col>
					<el-col :span="12">
						<el-form-item v-if="!user.id || user.changePasswordFlag" label="确认密码" prop="passwordAgain">
							<el-input v-model="user.passwordAgain" clearable type="password"/>
						</el-form-item>
					</el-col>
				</el-row>
			</el-form>
			<template #footer>
				<el-button v-auth="'sys-user:saveUser'" :disabled="editFormDisabled" icon="el-icon-CircleCheck" type="primary" @click="save">
					保存
				</el-button>
				<el-button icon="el-icon-CircleClose" type="warning" @click="dialogVisible = false">
					取消
				</el-button>
			</template>
		</el-dialog>

	</div>
</template>

<script lang="ts" name="UserManagement" setup>

import {clearUserDataApi, deleteUserApi, getAllRoleApi, getAllRoleByUserIdApi, saveUserApi, updateUserValidApi} from '@/api/system/user.api'
import {validateUsername} from '@/utils/validateUtil'
import type {RuleItemValidator} from '@/model/global-import'
import {h, nextTick, onActivated, onMounted, reactive, ref} from 'vue'
import type {FormInstance, FormRules} from 'element-plus'
import {ElMessageBox, type TableColumnCtx} from 'element-plus'
import {
	elTableDateTimeFormatter,
	elTableHeaderCellClassName,
	elTableSortChange,
	exist,
	focusFormErrorElement,
	getBusinessCodeName,
	handleAvatarUrl,
	initTableIndex,
	messageSuccess
} from '@/utils/commonUtil'
import {useI18n} from 'vue-i18n'
import CusPagination from '@/components/cus-pagination.vue'
import CusTableTitle from '@/components/cus-table-title.vue'
import {hasPermission} from '@/utils/authUtil'
import BusinessCodeSwitch from '@/components/business-code-switch.vue'
import BusinessCodeRadio from '@/components/business-code-radio.vue'
import type {DebouncedFunc} from 'lodash-es'
import {debounce, isEqual, map} from 'lodash-es'
import {calcMaxHeight} from '@/utils/layoutUtil'
import {useEventListener} from '@vueuse/core'
import {onBeforeRouteLeave, useRoute} from 'vue-router'
import {useUserStore} from '@/stores/modules/user.store'
import {routePush, updateDynamicRoutes} from '@/utils/routeUtil'
import router from '@/router'
import {homeRoute} from '@/router/static'
import {useNavTabsStore} from '@/stores/modules/navTabs.store'
import CusForm from '@/components/cus-form.vue'
import BusinessCodeCheckbox from '@/components/business-code-checkbox.vue'

const {t} = useI18n(),
		userStore = useUserStore(),
		navTabsStore = useNavTabsStore(),
		route = useRoute(),
		pageRef = ref(),
		tableRef = ref(),
		editFormRef = ref<FormInstance>(),
		tableMaxHeight = ref<number>(800),
		validSwitchLoading = ref(false),
		usernameValidator: RuleItemValidator = (rule, value, callback) => {
			if (validateUsername(value)) {
				callback()
			} else {
				callback(Error())
			}
		},
		validatePasswordAgain: RuleItemValidator = (rule, value, callback) => {
			if (value === user.password) {
				callback()
			} else {
				callback(Error())
			}
		},
		params = reactive<SearchUserRequest>({
			username_like: undefined,
			nickname_like: undefined,
			gender_eq: undefined,
			valid_eq: undefined,
			isDeleted_eq: undefined,
			introduction_like: undefined,
			hasEmail: undefined,
			email_like: undefined,
			orderby: []
		}),
		user = reactive<UserForm>({
			id: undefined,
			nickname: undefined,
			username: undefined,
			password: undefined,
			passwordAgain: undefined,
			salt: undefined,
			valid: 1,
			gender: undefined,
			email: undefined,
			emailValid: 0,
			avatar: undefined,
			introduction: undefined,
			changePasswordFlag: false,
			createTime: undefined,
			updateTime: undefined,
			roleList: []
		}),
		editFormDisabled = ref(false),
		roleOptionList = ref<SysRole[]>([]),
		userTableData = ref<SysUser[]>([]),
		dialogTitle = ref<string>(),
		dialogVisible = ref(false),
		tableLoading = ref(false),
		rules = reactive<FormRules>({
			nickname: [
				{required: true, message: '请输入昵称', trigger: 'change'},
				{min: 2, max: 10, message: '长度在 2 到 10 个字符', trigger: 'change'}
			],
			username: [
				{required: true, message: '请输入用户名', trigger: 'change'},
				{message: '①可以包英文含字母和数字 ②字母开头 ③长度为2-20', trigger: 'change', validator: usernameValidator}
			],
			roleList: [
				{required: true, message: '请选择角色', trigger: 'change', type: 'array'}
			],
			password: [
				{required: true, message: '请输入密码', trigger: 'change'},
				{min: 6, max: 50, message: '长度在 6 到 50 个字符', trigger: 'change'}
			],
			passwordAgain: [
				{required: true, validator: validatePasswordAgain, message: '两次输入的密码不一致', trigger: 'change'}
			],
			valid: [
				{required: true, message: '请选择用户状态', trigger: 'change'}
			],
			gender: [
				{required: true, message: '请选择性别', trigger: 'change'}
			],
			email: [
				{max: 320, message: '长度不超过 320 个字符', trigger: 'change'},
				{type: 'email', message: '邮箱格式不正确', trigger: 'change'}
			],
			emailValid: [
				{required: true, message: '请选择邮箱激活状态', trigger: 'change'}
			],
			emailNotifyTypes: [
				{required: true, message: '请选择邮箱通知类型', trigger: 'change', type: 'array'}
			],
			introduction: [
				{required: false, max: 500, message: '长度不超过 500 个字符', trigger: 'change'}
			]
		}),
		getTableMaxHeight: DebouncedFunc<() => typeof getTableMaxHeight> = debounce(() => {
			tableMaxHeight.value = calcMaxHeight('#user-form', '#user-table-title', '#user-pagination')
			return getTableMaxHeight
		}, 100, {
			leading: true,
			trailing: false,
			maxWait: 100
		}),
		handleHeaderCellClass = (args: { rows: SysUser[], column: TableColumnCtx<SysUser>, rowIndex: number, columnIndex: number }) => {
			elTableHeaderCellClassName(args, params.orderby)
		},
		handleSearch = () => {
			pageRef.value.reload()
		},
		resetParams = () => {
			params.nickname_like = undefined
			params.username_like = undefined
			params.gender_eq = undefined
			params.valid_eq = undefined
			params.isDeleted_eq = undefined
			params.introduction_like = undefined
			params.hasEmail = undefined
			params.email_like = undefined
			params.orderby = []
			// 清除多列的排序状态
			for (const column of tableRef.value?.store.states.columns.value) {
				column.order = null
			}
		},
		resetSearch = () => {
			resetParams()
			handleSearch()
		},
		resetUser = () => {
			user.id = undefined
			user.nickname = undefined
			user.username = undefined
			user.password = undefined
			user.passwordAgain = undefined
			user.salt = undefined
			user.valid = 1
			user.gender = undefined
			user.email = undefined
			user.emailValid = 0
			user.avatar = undefined
			user.introduction = undefined
			user.changePasswordFlag = false
			user.createTime = undefined
			user.updateTime = undefined
			user.roleList = []
		},
		toAdd = () => {
			resetUser()
			dialogVisible.value = true
			editFormDisabled.value = false
			dialogTitle.value = '新增用户'
			nextTick(() => {
				editFormRef.value!.clearValidate()
			})
		},
		save = () => {
			editFormRef.value?.validate((isValid: boolean) => {
				if (isValid) {
					saveUserApi(user).then(response => {
						if (user.id) {
							messageSuccess(t('successMessage.update'))
							// 如果修改的是自己的信息，且修改了用户名、昵称、角色中的任意一个，则需要更新token，同时更新userStore中的数据
							userStore.modifyToken(response.data?.token, response.data?.expire)
							const newUser = response.data?.user
							if (newUser) {
								let newRoleCodes: string[] | undefined = map(user.roleList, value => value.roleCode!)
								let newRoleNames: string[] | undefined = map(user.roleList, value => value.roleName!)
								if (isEqual(new Set(newRoleCodes), new Set(userStore.roleCodes))) {
									newRoleCodes = undefined
								}
								if (isEqual(new Set(newRoleNames), new Set(userStore.roleNames))) {
									newRoleNames = undefined
								}
								userStore.modifyUserInfo(newUser)
								if (newRoleCodes && newRoleCodes.length > 0) {
									userStore.roleCodes = newRoleCodes
								}
								if (newRoleNames && newRoleNames.length > 0) {
									userStore.roleNames = newRoleNames
								}
							}
							const isAdmin = response.data?.isAdmin
							if (exist(isAdmin)) {
								userStore.isAdmin = isAdmin
							}
							const buttons = response.data?.buttons
							if (buttons) {
								userStore.buttons = buttons
							}
							const menus = response.data?.menus
							if (menus) {
								userStore.dynamicMenus = menus
								// 更新动态路由
								updateDynamicRoutes()
								// 初始化菜单
								userStore.generateMenu()
								// 关闭所有没有权限的标签页
								navTabsStore.retainTheseTabs(menuVo => router.getRoutes().some(item => item.path === menuVo.meta.fullPath))
								// 如果当前路由已不存在，则跳转到首页
								if (!router.getRoutes().some(item => item.path === route.path)) {
									routePush(homeRoute)
									return
								}
							}
						} else {
							messageSuccess(t('successMessage.add'))
						}
						dialogVisible.value = false
						pageRef.value.buildData()
					})
				} else {
					focusFormErrorElement()
				}
			})
		},
		toUpdate = (row: SysUser) => {
			resetUser()
			Object.assign(user, JSON.parse(JSON.stringify(row)))
			if (!user.emailNotifyTypes) {
				user.emailNotifyTypes = []
			}
			// 查询该用户的身份
			getAllRoleByUserIdApi(row.id!).then(response => {
				user.roleList = response.data
				dialogTitle.value = '编辑用户信息'
				dialogVisible.value = true
				editFormDisabled.value = row.isDeleted === 1
			})
		},
		deleteUser = (row: SysUser) => {
			ElMessageBox({
				title: '删除该用户？',
				message: h('div', null, [
					h('p', null, `昵称：${row.nickname}`),
					h('p', null, `用户名：${row.username}`),
					h('br'),
					h('p', null, [h('b', null, '注意：'), '这会保留用户的所有数据，但是会更改该用户的用户名和昵称，同时该用户将无法登录系统。']),
					h('br'),
					h('p', null, '该操作无法恢复。')
				]),
				showCancelButton: true,
				showConfirmButton: true,
				confirmButtonText: '确定',
				cancelButtonText: '取消',
				type: 'warning',
				draggable: true
			}).then(() => {
				deleteUserApi(row.id!).then(() => {
					messageSuccess(t('successMessage.delete'))
					pageRef.value.buildData()
				})
			}).catch(() => {
			})
		},
		clearUserData = (row: SysUser) => {
			ElMessageBox({
				title: '彻底删除该用户？',
				message: h('div', null, [
					h('p', null, `昵称：${row.nickname}`),
					h('p', null, `用户名：${row.username}`),
					h('br'),
					h('p', null, [h('b', null, '注意：'), '将从数据库中删除该用户的所有数据，包括：用户基本信息、产线收藏、话题、评论、点赞、网站设置、操作日志。']),
					h('br'),
					h('p', null, '该操作无法恢复。')
				]),
				showCancelButton: true,
				showConfirmButton: true,
				confirmButtonText: '确定',
				cancelButtonText: '取消',
				type: 'warning',
				draggable: true
			}).then(() => {
				clearUserDataApi(row.id!).then(() => {
					messageSuccess(t('successMessage.delete'))
					pageRef.value.buildData()
				})
			}).catch(() => {
			})
		},
		beforeValidChange = async (row: SysUser) => {
			try {
				validSwitchLoading.value = true
				return await new Promise((resolve, reject) => {
					const newValue = row.valid! === 1 ? 0 : 1
					updateUserValidApi({id: row.id!, valid: newValue}).then(response => {
						const success = response.data
						if (success) {
							messageSuccess(`用户【${row.username}】${newValue === 0 ? '已禁用' : '已启用'}`)
							return resolve(true)
						} else {
							return reject(Error('更新失败'))
						}
					}).catch(error => {
						return reject(error)
					}).finally(() => {
						validSwitchLoading.value = false
					})
				})
			} catch {
				validSwitchLoading.value = false
			}
		}

getAllRoleApi().then(response => {
	roleOptionList.value = response.data
})

onMounted(() => {
	useEventListener(window, 'resize', getTableMaxHeight()!)
})

// 该页面开启缓存且首次或后续进入时执行，刷新页面不执行
onActivated(() => {
	useEventListener(window, 'resize', getTableMaxHeight()!)
})

onBeforeRouteLeave(() => {
	window.removeEventListener('resize', getTableMaxHeight)
})

</script>

<style lang="scss" scoped>
</style>
